グラデーションのチャットバブルを作成する
従来のチャット アプリはチャット バブルにメッセージを表示します 単色の背景。最新のチャット アプリの表示 に基づいたグラデーションを使用したチャットバブル 画面上の泡の位置。 このレシピでは、以下を実装してチャット UI を最新化します。 チャットバブルのグラデーション背景。
次のアニメーションはアプリの動作を示しています。
課題を理解する
従来のチャット バブル ソリューションでは、おそらくDecoratedBox
または同様のウィジェットを使用して丸いものをペイントします
各チャット メッセージの後ろにある四角形。そのアプローチは、
単色やグラデーションにも最適です。
すべてのチャットバブルで繰り返されます。しかしながら、現代では、
フルスクリーン、グラデーションバブルの背景には必要があります
別のアプローチ。全画面グラデーション、
画面を上下にスクロールするバブルと組み合わせて、
絵を描くためのアプローチが必要です
レイアウト情報に基づいて決定します。
各バブルの勾配には、次の知識が必要です。
画面上のバブルの位置。この意味は
ペイント動作にはレイアウト情報へのアクセスが必要です。
このような描画動作は、一般的なウィジェットでは不可能です
なぜならウィジェットは次のようなものだからですContainer
とDecoratedBox
レイアウトが行われる前に背景色を決定します。
その後ではありません。この場合、カスタムペイントが必要となるため、
動作しますが、カスタム レイアウト動作は必要ありません
またはカスタム ヒット テスト動作、CustomPainter
は
仕事をやり遂げるには素晴らしい選択です。
元の背景ウィジェットを置き換える
描画を担当するウィジェットを置き換えます。
という新しいステートレス ウィジェットが背景に追加されましたBubbleBackground
。を含めるcolors
財産を
あるべき全画面のグラデーションを表します。
バブルに適用されます。
BubbleBackground(
// The colors of the gradient, which are different
// depending on which user sent this message.
colors: message.isMine
? const [Color(0xFF6C7689), Color(0xFF3A364B)]
: const [Color(0xFF19B7FF), Color(0xFF491CCB)],
// The content within the bubble.
child: DefaultTextStyle.merge(
style: const TextStyle(
fontSize: 18.0,
color: Colors.white,
),
child: Padding(
padding: const EdgeInsets.all(12),
child: Text(message.text),
),
),
);
カスタム ペインタを作成する
次に、次の実装を紹介します。BubbleBackground
ステートレスなウィジェットとして。現時点では、build()
を返すメソッドCustomPaint
とともにCustomPainter
呼ばれたBubblePainter
。BubblePainter
塗装に使用されます
バブルのグラデーション。
@immutable
class BubbleBackground extends StatelessWidget {
const BubbleBackground({
super.key,
required this.colors,
this.child,
});
final List<Color> colors;
final Widget? child;
@override
Widget build(BuildContext context) {
return CustomPaint(
painter: BubblePainter(
colors: colors,
),
child: child,
);
}
}
class BubblePainter extends CustomPainter {
BubblePainter({
required List<Color> colors,
}) : _colors = colors;
final List<Color> _colors;
@override
void paint(Canvas canvas, Size size) {
// TODO:
}
@override
bool shouldRepaint(BubblePainter oldDelegate) {
// TODO:
return false;
}
}
スクロール情報へのアクセスを提供する
のCustomPainter
必要な情報が必要です
気泡が内部のどこにあるかを判断するListView
の境界、
としても知られていますViewport
。場所を決定するには次のことが必要です
先祖への言及ScrollableState
そして、への参照BubbleBackground
のBuildContext
。それぞれをCustomPainter
。
BubblePainter(
colors: colors,
bubbleContext: context,
scrollable: ScrollableState(),
),
class BubblePainter extends CustomPainter {
BubblePainter({
required ScrollableState scrollable,
required BuildContext bubbleContext,
required List<Color> colors,
}) : _scrollable = scrollable,
_bubbleContext = bubbleContext,
_colors = colors;
final ScrollableState _scrollable;
final BuildContext _bubbleContext;
final List<Color> _colors;
@override
bool shouldRepaint(BubblePainter oldDelegate) {
return oldDelegate._scrollable != _scrollable ||
oldDelegate._bubbleContext != _bubbleContext ||
oldDelegate._colors != _colors;
}
}
フルスクリーンのバブルグラデーションをペイントする
のCustomPainter
希望のグラデーションカラーになりました。
含まれているものへの参照ScrollableState
、
そしてこのバブルへの言及BuildContext
。
これがすべての情報です。CustomPainter
する必要があります
フルスクリーンのバブルグラデーションをペイントします。
を実装します。paint()
位置を計算する方法
バブルの、指定された色でシェーダーを構成し、
次に、マトリックス変換を使用してシェーダーをオフセットします。
内のバブルの位置に基づいて、Scrollable
。
class BubblePainter extends CustomPainter {
BubblePainter({
required ScrollableState scrollable,
required BuildContext bubbleContext,
required List<Color> colors,
}) : _scrollable = scrollable,
_bubbleContext = bubbleContext,
_colors = colors;
final ScrollableState _scrollable;
final BuildContext _bubbleContext;
final List<Color> _colors;
@override
bool shouldRepaint(BubblePainter oldDelegate) {
return oldDelegate._scrollable != _scrollable ||
oldDelegate._bubbleContext != _bubbleContext ||
oldDelegate._colors != _colors;
}
@override
void paint(Canvas canvas, Size size) {
final scrollableBox = _scrollable.context.findRenderObject() as RenderBox;
final scrollableRect = Offset.zero & scrollableBox.size;
final bubbleBox = _bubbleContext.findRenderObject() as RenderBox;
final origin =
bubbleBox.localToGlobal(Offset.zero, ancestor: scrollableBox);
final paint = Paint()
..shader = ui.Gradient.linear(
scrollableRect.topCenter,
scrollableRect.bottomCenter,
_colors,
[0.0, 1.0],
TileMode.clamp,
Matrix4.translationValues(-origin.dx, -origin.dy, 0.0).storage,
);
canvas.drawRect(Offset.zero & size, paint);
}
}
おめでとう!これで、最新のチャット バブル UI が完成しました。
要約
に基づいてペイントする場合の基本的な課題
スクロール位置、または一般的な画面位置、
ペイント動作は、
レイアウト段階が完了しました。CustomPaint
ユニークです
カスタムペイントを実行できるウィジェット
レイアウトフェーズが完了した後の動作。
レイアウトフェーズの後にペイントビヘイビアーを実行すると、
レイアウトに基づいてペイントを決定できます
の位置などの情報CustomPaint
内のウィジェットScrollable
または画面内で。